package io.github.openfeign.spring.enhancer;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;

/**
 * HTTP实体消费者模式转换器
 *
 * <h3>核心功能：</h3>
 * <ul>
 *   <li>为HTTP实体类注入延迟输出支持能力</li>
 *   <li>通过字节码增强实现以下改造：
 *     <ol>
 *       <li>创建支持消费者模式的新实体类</li>
 *       <li>重写输出流写入逻辑</li>
 *       <li>实现请求体生成与传输的解耦</li>
 *     </ol>
 *   </li>
 * </ul>
 *
 * <h3>新增组件说明：</h3>
 * <div class="component">
 *   <h4>ConsumerHttpEntity</h4>
 *   <p>核心扩展点实现，主要特性：</p>
 *   <pre>{@code
 *   public class ConsumerHttpEntity extends BasicHttpEntity {
 *       private Consumer delayOutput;  // 延迟输出控制器
 *
 *       // 核心方法重写
 *       public void writeTo(OutputStream os) {
 *           delayOutput.accept(os);    // 触发延迟写入操作
 *       }
 *   }
 *   }</pre>
 *   <ul>
 *     <li><strong>生命周期绑定：</strong>将输出流的实际写入操作延迟到传输阶段</li>
 *     <li><strong>流式接入点：</strong>通过accept方法暴露输出流控制权</li>
 *     <li><strong>继承兼容：</strong>保持与BasicHttpEntity的兼容性</li>
 *   </ul>
 * </div>
 *
 * @see org.apache.http.entity.BasicHttpEntity 基础HTTP实体类
 * @see java.util.function.Consumer 消费者接口
 */
@Slf4j
public class ConsumerHttpEntityBytecodeTransformer extends AbstractBytecodeTransformer {

    public ConsumerHttpEntityBytecodeTransformer(final ClassPool classPool, final String classOutPath) {
        super(classPool, classOutPath);
    }


    /**
     * {@inheritDoc}
     */
    public void transformBytecode() throws NotFoundException, CannotCompileException {
        if(log.isDebugEnabled()){
            log.debug("Start create org.apache.http.entity.ConsumerHttpEntity");
        }
        // 创建子类 ConsumerHttpEntity
        final CtClass ctClass = classPool.makeClass("org.apache.http.entity.ConsumerHttpEntity");
        ctClass.setSuperclass(classPool.get("org.apache.http.entity.BasicHttpEntity"));

        // 添加 outStream 字段
        final CtClass consumerClass = classPool.getCtClass("java.util.function.Consumer");
        final CtField outStreamField = new CtField(consumerClass, "delayOutput", ctClass);
        outStreamField.setModifiers(Modifier.PRIVATE); // 设置为私有字段
        ctClass.addField(outStreamField);

        // 添加构造方法
        final CtConstructor constructor = new CtConstructor(new CtClass[]{consumerClass}, ctClass);
        constructor.setBody("{ super(); $0.delayOutput = $1; }");
        ctClass.addConstructor(constructor);

        // 重写 writeTo 方法
        final CtMethod writeToMethod = new CtMethod(
                CtClass.voidType,
                "writeTo",
                new CtClass[]{classPool.get("java.io.OutputStream")},
                ctClass
        );
        writeToMethod.setModifiers(Modifier.PUBLIC);
        writeToMethod.setBody("{ $0.delayOutput.accept($1); }"); // 调用 Consumer 的 accept 方法
        ctClass.addMethod(writeToMethod);
        // 应用修改
        redefineClassInMemory(ctClass);
        if(log.isDebugEnabled()){
            log.debug("Successfully create org.apache.http.entity.ConsumerHttpEntity");
        }
    }


}
